
#include "tools_util.h"
#include <arpa/inet.h>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <netdb.h>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <vector>
#include "./../../log_module/log_module_define.h"

void GetAddrInfo(UrlInfo & url_info)
{
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family   = AF_INET;
    hints.ai_flags    = AI_PASSIVE;

    struct addrinfo * result = nullptr;
    std::string server_name = url_info.protocol.empty() ? std::to_string(url_info.port) : url_info.protocol;
    int ret = getaddrinfo(url_info.domain.c_str(), server_name.c_str(), &hints, &result);
    if (ret != 0)
    {
        std::string reason = gai_strerror(ret);
        ERROR("getaddrinfo result : {} and reason : {}", ret, reason);
    }
    else
    {
        char server_ip[128];
        for (struct addrinfo * ptr = result; ptr; ptr = ptr->ai_next)
        {
            struct sockaddr * sa_ptr = ptr->ai_addr;
            if (ptr->ai_family == AF_INET)
            {
                struct sockaddr_in * sai_ptr = (struct sockaddr_in*)sa_ptr;
                memset(server_ip, 0, sizeof(server_ip));
                inet_ntop(sai_ptr->sin_family, &sai_ptr->sin_addr.s_addr, server_ip, sizeof(server_ip));
                uint16_t port = ntohs(sai_ptr->sin_port);
                url_info.server_vec.push_back({.ip=server_ip,.port = port});
            }
        }
        freeaddrinfo(result);
    }
}

bool GetServerAddrInfo(const std::string & url, UrlInfo & url_info)
{
    url_info = ParseUrlData(url);
    if (url_info.domain.empty() || (url_info.port == 0 && url_info.protocol.empty()))
    {
        return false; 
    }
    GetAddrInfo(url_info);
    return true;
}

UrlInfo ParseUrlData(const std::string & url)
{
    UrlInfo result;
    auto index = url.find("://");
    if (index == std::string::npos)
    {
        return result;
    }
    result.protocol = url.substr(0, index);
    auto port_index =  url.find_first_of(':', index + 1);
    if (port_index != std::string::npos)
    {
        result.domain = url.substr(index + 3, port_index - index - 3);
        auto end_index = url.find_first_of('/', port_index + 1) ;
        if (end_index == std::string::npos)
        {
            result.port = atoi(url.substr(port_index + 1).c_str());
        }
        else
        {
            result.port = atoi(url.substr(port_index + 1, end_index - port_index).c_str());
            result.resource_path = url.substr(end_index);
        }
    }
    else
    {
        auto uri_index = url.find_first_of('/', index + 3);
        if (uri_index == std::string::npos)
        { 
            result.domain = url.substr(index + 3);
        }
        else
        {
            result.domain = url.substr(index + 3, uri_index - index - 3);
            result.resource_path = url.substr(uri_index);
        }
    }
    return result;
}
